home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / comm / tcp / Amster.lha / Amster_Install / Source / transfer.c < prev    next >
C/C++ Source or Header  |  2000-07-31  |  12KB  |  505 lines

  1. /*
  2. ** Amster - Transfer
  3. ** by Jacob Laursen <laursen@myself.com>
  4. */
  5.  
  6. #include "include/config.h"
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #include <proto/dos.h>
  12. #include <proto/exec.h>
  13. #include <proto/socket.h>
  14.  
  15. #include <netdb.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <netinet/tcp.h>
  20. #include <bsdsocket/socketbasetags.h>
  21. #include <error.h>
  22. #include <time.h>
  23.  
  24. #include "include/mui.h"
  25. #include <MUI/NListview_mcc.h>
  26. #include "include/download.h"
  27. #include "include/upload.h"
  28. #include "include/gui.h"
  29. #include "include/panel.h"
  30. #include "include/prefs.h"
  31. #include "include/transfer.h"
  32. #include "amster_Cat.h"
  33. #include "include/protos.h"
  34.  
  35.  
  36. MUIF translistdisp(REG(a2) char **array, REG(a1) songtrans sd)
  37. {
  38.     static char bufd2[50], bufd3[50], bufd4[50], bufd5[50];
  39.     static char bufu2[50], bufu3[50], bufu4[50], bufu5[50];
  40.     char *buf2, *buf3, *buf4, *buf5;
  41.  
  42.     static char *states[] = {
  43.         (char *)_MSG_TRANS_STAT_PREPARE,
  44.         (char *)_MSG_TRANS_STAT_QUEUE,
  45.         (char *)_MSG_TRANS_STAT_WAIT,
  46.         (char *)_MSG_TRANS_STAT_CONN,
  47.         (char *)_MSG_TRANS_STAT_REQ,
  48.         (char *)_MSG_TRANS_STAT_INIT,
  49.         (char *)_MSG_TRANS_STAT_DL,
  50.         (char *)_MSG_TRANS_STAT_UL,
  51.         (char *)_MSG_TRANS_STAT_FIN,
  52.         (char *)_MSG_TRANS_STAT_ABORT,
  53.         (char *)_MSG_TRANS_STAT_ERROR,
  54.         NULL
  55.     };
  56.  
  57.     static char *errors[] = {
  58.         (char *)_MSG_TRANS_STAT_ERROR,
  59.         (char *)_MSG_TRANS_ERROR_FILEOPEN,
  60.         (char *)_MSG_TRANS_ERROR_FILEREAD,
  61.         (char *)_MSG_TRANS_ERROR_FILEWRITE,
  62.         (char *)_MSG_TRANS_ERROR_NET_UNKNOWN,
  63.         (char *)_MSG_TRANS_ERROR_LOGGEDOUT,
  64.         (char *)_MSG_TRANS_ERROR_NOTFOUND,
  65.         (char *)_MSG_TRANS_ERROR_INVALIDREQUEST,
  66.         (char *)_MSG_TRANS_ERROR_TEASER,
  67.         (char *)_MSG_TRANS_ERROR_BUSY,
  68.         (char *)_MSG_TRANS_ERROR_NOTREQ,
  69.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  70.         NULL
  71.     };
  72.  
  73.     static char *NetError[] = {
  74.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  75.         (char *)_MSG_TRANS_ERROR_NET_REFUSED,
  76.         (char *)_MSG_TRANS_ERROR_NET_RESET,
  77.         (char *)_MSG_TRANS_ERROR_NET_PIPE,
  78.         NULL
  79.     };
  80.  
  81.     if (states[0] == (char *)_MSG_TRANS_STAT_PREPARE)
  82.         localize_array(states);
  83.  
  84.     if (errors[0] == (char *)_MSG_TRANS_STAT_ERROR)
  85.         localize_array(errors);
  86.  
  87.     if (NetError[0] == (char *)_MSG_TRANS_ERROR_NET_TIMEOUT)
  88.         localize_array(NetError);
  89.  
  90.     if (sd) {
  91.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  92.             buf2 = bufd2;
  93.             buf3 = bufd3;
  94.             buf4 = bufd4;
  95.             buf5 = bufd5;
  96.         }
  97.         else {
  98.             buf2 = bufu2;
  99.             buf3 = bufu3;
  100.             buf4 = bufu4;
  101.             buf5 = bufu5;
  102.         }
  103.  
  104.         *array++ = nap_strippath(sd->song->title);
  105.  
  106.         if (sd->state == DLS_WAIT) {
  107.             sprintf(buf5, states[sd->state], sd->ErrorCode);
  108.             *array++ = buf5;
  109.         }
  110.         else if (sd->state != DLS_ERROR)
  111.             *array++ = states[sd->state];
  112.         else {
  113.             switch (sd->error) {
  114.                 case ERROR_FILEOPEN:
  115.                 case ERROR_FILEREAD:
  116.                 case ERROR_FILEWRITE:
  117.                     sprintf(buf5, errors[sd->error], sd->ErrorCode);
  118.                     *array++ = buf5;
  119.                     break;
  120.                 case ERROR_NET:
  121.                     switch (sd->ErrorCode) {
  122.                         case ETIMEDOUT:
  123.                             *array++ = NetError[ERROR_NET_TIMEOUT];
  124.                             break;
  125.                         case ECONNREFUSED:
  126.                             *array++ = NetError[ERROR_NET_REFUSED];
  127.                             break;
  128.                         case ECONNRESET:
  129.                             *array++ = NetError[ERROR_NET_RESET];
  130.                             break;
  131.                         case EPIPE:
  132.                             *array++ = NetError[ERROR_NET_PIPE];
  133.                             break;
  134.                         default:
  135.                             sprintf(buf5, errors[sd->error], sd->ErrorCode);
  136.                             *array++ = buf5;
  137.                     }
  138.                     break;
  139.                 default:
  140.                     *array++ = errors[sd->error];
  141.             }
  142.         }
  143.  
  144.         if (sd->size > 0)
  145.             sprintf(buf2,"\33r%ld / %ld (%d%%)", sd->cur, sd->size, (sd->cur*100+5)/sd->size);
  146.         else sprintf(buf2, "\33r0");    /* Can this happen? */
  147.         *array++ = buf2;
  148.  
  149.         if (sd->cps > 0) {
  150.             if (sd->stalltick < 5 || sd->state >= DLS_FIN) {    /* 5 seconds */
  151.                 sprintf(buf3, "%d", sd->cps);
  152.                 *array++ = buf3;
  153.             }
  154.             else {
  155.                 *array++ = (char *)MSG_TRANS_STAT_STALLED;
  156.             }
  157.             sprintf(buf4, "%ld:%02ld / %ld:%02ld", sd->transtime/60, sd->transtime%60, sd->timeleft/60, sd->timeleft%60);
  158.             *array = buf4;
  159.         }
  160.         else {
  161.             *array++ = "-";
  162.             *array   = "-";
  163.         }
  164.  
  165.     }
  166.     else {
  167.         *array++ = (char *)MSG_LH_FILE;
  168.         *array++ = (char *)MSG_LH_STATE;
  169.         *array++ = (char *)MSG_LH_SIZE;
  170.         *array++ = (char *)MSG_LH_CPS;
  171.         *array =   (char *)MSG_LH_ETIME;
  172.     }
  173.     return 0;
  174. }
  175.  
  176.  
  177. MUIF translistdest(REG(a2) APTR pool, REG(a1) songtrans sd)
  178. {
  179.     nap_songfree(sd->song);
  180.     if (sd->fname) free(sd->fname);
  181.     free(sd);
  182.  
  183.     return 0;
  184. }
  185.  
  186.  
  187. ULONG dl_setup(struct IClass *cl, Object *obj, Msg msg)
  188. {
  189.     struct TransferData *data = INST_DATA(cl, obj);
  190.  
  191.     if (!DoSuperMethodA(cl, obj, msg))
  192.         return(FALSE);
  193.  
  194.     DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->ihnode);
  195. /*    DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);*/
  196.  
  197.     return(TRUE);
  198. }
  199.  
  200.  
  201. ULONG dl_muicleanup(struct IClass *cl, Object *obj, Msg msg)
  202. {
  203.     struct TransferData *data = INST_DATA(cl,obj);
  204.  
  205.     DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->ihnode);
  206. /*    DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);*/
  207.  
  208.     return(DoSuperMethodA(cl,obj,msg));
  209. }
  210.  
  211.  
  212. void CalculateCps(songtrans sd)
  213. {
  214.     if (sd->cur != sd->oldsize) {
  215.         sd->stalltick = 0;
  216.         sd->oldsize = sd->cur;
  217.     }
  218.     else sd->stalltick++;
  219.  
  220.     sd->transtime = time(NULL) - sd->starttime;
  221.     if (sd->transtime == 0) sd->transtime = 1;
  222.     sd->cps = (sd->cur - sd->resumestart) / sd->transtime;
  223.     if (sd->cps > 0)
  224.         sd->timeleft = (sd->size - sd->cur) / sd->cps;
  225.     else sd->timeleft = 0;
  226. }
  227.  
  228.  
  229. void TransferSetError(struct TransferData *data, char *title, char *user, int error)
  230. {
  231.     u_long tmp;
  232.     songtrans sd;
  233.     long i;
  234.  
  235.     for (i=0; ; i++) {
  236.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  237.         if (!tmp) return;
  238.         sd = (songtrans)tmp;
  239.         if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
  240.     }
  241.  
  242.     if ((sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) && sd->state == DLS_PREP) {
  243.         DoMethod(gui->dwin, DL_COUNTDECREMENT);
  244.     }
  245.  
  246.     sd->state = DLS_ERROR;
  247.     sd->error = error;
  248.  
  249.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  250.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  251. }
  252.  
  253.  
  254. void TransferInfo(struct TransferData *data)
  255. {
  256.     static char bufd[600], bufu[600];
  257.     char *buf;
  258.     u_long tmp;
  259.     songtrans sd;
  260.  
  261.     GetAttr(MUIA_NList_EntryClick,  data->list, &tmp);
  262.     if (tmp == -1 || tmp == -2) return;
  263.     DoMethod(data->list, MUIM_NList_GetEntry, tmp, &sd);
  264.     if (!sd) return;
  265.  
  266.     if (sd->song->ip == 0) return;
  267.  
  268.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) buf = bufd;
  269.     else buf = bufu;
  270.  
  271.     if (sd->host[0] == '\0') {
  272.         sprintf(buf, "%s (%d.%d.%d.%d)", sd->song->user, (sd->song->ip&0xFF000000)>>24, (sd->song->ip&0xFF0000)>>16, (sd->song->ip&0xFF00)>>8, sd->song->ip&0xFF);
  273.     }
  274.     else {
  275.         sprintf(buf, "%s (%s)", sd->song->user, sd->host);
  276.     }
  277.  
  278.     set(data->info, MUIA_Text_Contents, buf);
  279. }
  280.  
  281.  
  282. void TransferAbort(struct TransferData *data)
  283. {
  284.     u_long item;
  285.     songtrans sd;
  286.  
  287.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  288.     if (!item) return;
  289.  
  290.     sd = (songtrans)item;
  291.  
  292.     if (sd->state >= DLS_FIN) {
  293.         return;
  294.     }
  295.  
  296.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  297.         if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
  298.         if (sd->state == DLS_QUEUE) QueueCount--;
  299.     }
  300.  
  301.     if (sd->t) {
  302.         th_message(sd->t, THC_EXIT, 0);
  303.         Signal(sd->t->task, SIGBREAKF_CTRL_C);
  304.     }
  305.     else {
  306.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  307.             if (sd->state != DLS_QUEUE && sd->state != DLS_WAIT) {
  308.                 DoMethod(gui->dwin, DL_COUNTDECREMENT);
  309.             }
  310.         }
  311.         else DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  312.     }
  313.  
  314.     sd->state = DLS_ABORT;
  315.  
  316.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  317.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  318. }
  319.  
  320.  
  321. void TransferCleanup(struct TransferData *data)
  322. {
  323.     u_long item;
  324.     int i=0;
  325.  
  326.     set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
  327.     while (1) {
  328.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  329.         if (!item) break;
  330.         if (((songtrans)item)->state >= DLS_FIN) DoMethod(data->list, MUIM_NList_Remove, i);
  331.         else i++;
  332.     }
  333.     set(data->list,MUIA_NList_Quiet, MUIV_NList_Quiet_None);
  334. }
  335.  
  336.  
  337. void TransferCleanupSingle(struct TransferData *data, songtrans sd)
  338. {
  339.     long pos;
  340.  
  341.     pos = MUIV_NList_GetPos_Start;
  342.     DoMethod(data->list, MUIM_NList_GetPos, sd, &pos);
  343.     DoMethod(data->list, MUIM_NList_Remove, pos);
  344. }
  345.  
  346.  
  347. void TransferWatcher(struct TransferData *data)
  348. {
  349.     u_long item;
  350.     long i;
  351.     songtrans sd;
  352.  
  353.     for (i=0; ; i++) {
  354.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  355.         if (!item) break;
  356.         sd = (songtrans)item;
  357.         if (sd->state == DLS_PREP) {
  358.             if (time(NULL)-sd->reqtime > 120) {    /* We consider this transfer dead/hanging (never started) */
  359.                 sd->state = DLS_ERROR;
  360.                 sd->error = ERROR_TIMEOUT;
  361.                 if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  362.                     DoMethod(gui->dwin, DL_COUNTDECREMENT);
  363.                     DoMethod(gui->dwin, DL_UPDATE, sd);
  364.                 }
  365.                 else {
  366.                     DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  367.                     DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  368.                 }
  369.             }
  370.         }
  371.     }
  372. }
  373.  
  374.  
  375. void TransferHandleError(songtrans sd)
  376. {
  377.     char error[128];
  378.  
  379.     if (sd->ErrorCode == EINTR) return;    /* Aborted with CTRL-C */
  380.  
  381.     if (sd->error != 0) {
  382.         sd->state = DLS_ERROR;
  383.         if (sd->error >= ERROR_FILEOPEN && sd->error <= ERROR_FILEWRITE) {
  384.             Fault(sd->ErrorCode, "", error, 127);
  385.             gui_debugf((char *)MSG_INFO_IOERROR, sd->fname, error);
  386.         }
  387.         else if (sd->error >= ERROR_OUTOFBOUND) sd->error = ERROR_UNKNOWN;
  388.         prf_event(PRFE_DLERROR, sd->fname);
  389.     }
  390.     else if (sd->state == DLS_FIN) {
  391.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) prf_event(PRFE_DLFINISH, sd->fname);
  392.         else prf_event(PRFE_ULFINISH, sd->fname);
  393.     }
  394.  
  395.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  396.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  397. }
  398.  
  399.  
  400. /* Thread stuff */
  401.  
  402. BOOL InitTransferThread(thread t, songtrans sd)
  403. {
  404.     struct Library *DosBase;
  405.     struct Library *SocketBase;
  406.     char *buffer;
  407.     long s;
  408.     long tmp;
  409.     struct hostent *he;
  410.  
  411.     sd->state = DLS_PREP;
  412.  
  413.     sd->nsig = AllocSignal(-1);
  414.     if (sd->nsig == -1) {
  415.         ExitTransferThread(sd, 49);
  416.         return FALSE;
  417.     }
  418.     sd->nsigm = (1L << (sd->nsig));
  419.     sd->msigm = (1L << (t->port->mp_SigBit));
  420.  
  421.     DosBase = OpenLibrary("dos.library", 0);
  422.     if (!DosBase) {
  423.         ExitTransferThread(sd, 50);
  424.         return FALSE;
  425.     }
  426.     sd->DosBase = DosBase;
  427.  
  428.     SocketBase = OpenLibrary("bsdsocket.library", 0);
  429.     if (!SocketBase) {
  430.         ExitTransferThread(sd, 51);
  431.         return FALSE;
  432.     }
  433.     sd->SocketBase = SocketBase;
  434.  
  435.     SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)sd->nsigm, TAG_DONE);
  436.  
  437.     buffer = malloc(8192);
  438.     if (!buffer) {
  439.         ExitTransferThread(sd, 52);
  440.         return FALSE;
  441.     }
  442.     sd->buffer = buffer;
  443.  
  444.     /* Perform DNS-lookup */
  445.     he = gethostbyname(Inet_NtoA(sd->song->ip));
  446.     he = gethostbyaddr(he->h_addr_list[0], he->h_length, AF_INET);
  447.     if (he != 0) strcpy(sd->host, he->h_name);
  448.     else strcpy(sd->host, Inet_NtoA(sd->song->ip));
  449.  
  450.     s = socket(AF_INET, SOCK_STREAM, 0);
  451.     if (s < 0) {
  452.         ExitTransferThread(sd, 53);
  453.         return FALSE;
  454.     }
  455.     sd->s = s;
  456.  
  457.     sd->sin.sin_addr.s_addr = sd->ip;
  458.     sd->sin.sin_port = htons(sd->port);
  459.     sd->sin.sin_family = AF_INET;
  460.     sd->sin.sin_len = sizeof(sd->sin);
  461.  
  462.     tmp = 1;
  463.     IoctlSocket(s, FIOASYNC, (char *)&tmp);
  464.     IoctlSocket(s, FIONBIO,  (char *)&tmp);
  465.     /* Asynchronous and non-blocking I/O to the socket */
  466.  
  467.     tmp = connect(s, (struct sockaddr *)&sd->sin, sizeof(sd->sin));
  468.     if (tmp == -1 && Errno() != EINPROGRESS) {
  469.         sd->ErrorCode = Errno();
  470.         ExitTransferThread(sd, ERROR_NET);
  471.         return FALSE;
  472.     }
  473.  
  474.     thr_message(t, DLC_STATE, (APTR)DLS_CON);
  475.  
  476.     return TRUE;
  477. }
  478.  
  479.  
  480. void ExitTransferThread(songtrans sd, int ret)
  481. {
  482.     struct Library *DosBase=sd->DosBase;
  483.     struct Library *SocketBase=sd->SocketBase;
  484.  
  485.     if (sd->nsig != -1) FreeSignal(sd->nsig);
  486.     sd->nsig = -1;
  487.  
  488.     if (sd->f) Close(sd->f);
  489.     sd->f = 0;
  490.  
  491.     if (sd->s != -1) CloseSocket(sd->s);
  492.     sd->s = -1;
  493.  
  494.     if (sd->buffer) free(sd->buffer);
  495.     sd->buffer = NULL;
  496.  
  497.     if (SocketBase) CloseLibrary(SocketBase);
  498.     sd->SocketBase = NULL;
  499.  
  500.     if (DosBase) CloseLibrary(DosBase);
  501.     sd->DosBase = NULL;
  502.  
  503.     thr_exit(sd->t, ret);
  504. }
  505.